#include "iic.h"
#include "fsl_debug_console.h"
union LenData iic_lendata;
uint16_t delaytimes;
void SetSoftIIC_Config(enum IIC_FQ fq)
{
	GPIO_PinWrite(SOFT_SCL_GPIO, SOFT_SCL_PORT,SOFT_SCL_PIN, 1);
	GPIO_PinWrite(SOFT_SDA_GPIO, SOFT_SDA_PORT,SOFT_SDA_PIN, 1);
	switch (fq)
	//设置通讯速率
	{
	case 400:
		delaytimes = 0;
		break;
	case 300:
		delaytimes = 1;
		break;
	case 200:
		delaytimes = 2;
		break;
	case 100:
		delaytimes = 3;
		break;
	default:
		delaytimes = fq;
		break;
	}
}
inline static void GPIO_SCL_OutStatus(uint8_t status)
{
	GPIO_PinWrite(SOFT_SCL_GPIO, SOFT_SCL_PORT,SOFT_SCL_PIN, status);
}
inline static void GPIO_SDA_OutStatus(uint8_t status)
{
	GPIO_PinWrite(SOFT_SDA_GPIO, SOFT_SDA_PORT,SOFT_SDA_PIN, status);
}
inline static uint32_t GPIO_SDA_InStatus()
{
	return GPIO_PinRead(SOFT_SDA_GPIO,SOFT_SDA_PORT, SOFT_SDA_PIN);
}
inline static void usDelay(uint32_t delayTime_us)
{
	SDK_DelayAtLeastUs(delayTime_us, CLOCK_GetCoreSysClkFreq());
}
/**
 * @brief  IIC产生一个起始信号
 * @param  IIC端口
 * @retval 无
 */
void Soft_iic_start()
{
	SDA_OUT();       // sda输出
	GPIO_SDA_OutStatus(1);
	GPIO_SCL_OutStatus(1);
	//	SOFT_IIC_SDA = 1;
	//	SOFT_IIC_SCL = 1;
	usDelay(delaytimes);
	GPIO_SDA_OutStatus(0);
	// 	SOFT_IIC_SDA = 0;       // START:when CLK is high,DATA change form high to low
	usDelay(delaytimes);
	GPIO_SCL_OutStatus(0);
	//	SOFT_IIC_SCL = 0;       // 起始位：SCL为高电平期间    SDA出现下降沿
}
/**
 * @brief  IIC产生一结束信号
 * @param  IIC端口
 * @retval 无
 */
void Soft_iic_stop()
{
	SDA_OUT();
	GPIO_SCL_OutStatus(0);
	GPIO_SDA_OutStatus(0);
	//	SOFT_IIC_SCL = 0;
	//	SOFT_IIC_SDA = 0;//STOP:when CLK is high DATA change form low to high

	usDelay(delaytimes);
	GPIO_SCL_OutStatus(1);
	GPIO_SDA_OutStatus(1);
	//	SOFT_IIC_SCL = 1;
	//	SOFT_IIC_SDA = 1;//终止位：SCL为高电平期间 SDA出现上升沿
	usDelay(delaytimes);
}
/**
 * @brief  应答信号
 * 当IIC主机（不一定是发送端还是接受端）将8位数据或命令传出后，会将SDA信号设置为输入，等待从机应答（等待SDA由高电平拉为低电平）
 * 若从机正确应答，表明数据或者命令传输成功，否则传输失败，注意，应答信号是数据接收方发送给数据发送方的。
 * @param
 * @retval
 */
inline int8_t Soft_wait_ack()
{
	uint16_t ucErrTime = 0;
	GPIO_SDA_OutStatus(1);
	//	SOFT_IIC_SDA = 1;
	SDA_IN();                        // SDA
	usDelay(delaytimes);
	GPIO_SCL_OutStatus(1);
	//	SOFT_IIC_SCL = 1;
	usDelay(delaytimes);
	while (GPIO_SDA_InStatus()) //SOFT_IIC_SDA_READ
	{
		ucErrTime++;
		if (ucErrTime > 30000)
		{
			Soft_iic_stop();
			PRINTF("iic wait ack timeout");
			return -1;
		}
	}
	GPIO_SCL_OutStatus(0);
	//	SOFT_IIC_SCL = 0;
	return 0;
}
/**
 * @brief  发送应答信号
 * @param
 * @retval
 */
inline void Soft_iic_ack()
{
	GPIO_SCL_OutStatus(0);
	;
	//	SOFT_IIC_SCL = 0;
	SDA_OUT();
	GPIO_SDA_OutStatus(0);
	//	SOFT_IIC_SDA= 0;
	usDelay(delaytimes);
	GPIO_SCL_OutStatus(1);
	//	SOFT_IIC_SCL = 1;
	usDelay(delaytimes);
	GPIO_SCL_OutStatus(0);
	//	SOFT_IIC_SCL = 0;
}

/**
 * @brief  发送非应答信号
 * @param
 * @retval
 */
void Soft_iic_nack()
{
	GPIO_SCL_OutStatus(0);
	//	SOFT_IIC_SCL = 0;
	SDA_OUT();
	GPIO_SDA_OutStatus(1);
	//	SOFT_IIC_SDA = 1;
	usDelay(delaytimes);
	GPIO_SCL_OutStatus(1);
	//	SOFT_IIC_SCL = 1;
	usDelay(delaytimes);
	GPIO_SCL_OutStatus(0);
	//	SOFT_IIC_SCL = 0;
}
/**
 * @brief  IIC发送一个字节
 * @param
 * @retval
 */
void Soft_iic_Write(int8_t data)
{
	uint8_t t;
	SDA_OUT();
	GPIO_SCL_OutStatus(0);
	//    SOFT_IIC_SCL = 0;//
	for (t = 0; t < 8; t++)
	{
		if ((data & 0x80) >> 7)
			GPIO_SDA_OutStatus(1);
		//			SOFT_IIC_SDA = 1;
		else
			GPIO_SDA_OutStatus(0);
		//			SOFT_IIC_SDA = 0;
		data <<= 1;
		usDelay(delaytimes);
		GPIO_SCL_OutStatus(1);
		//		SOFT_IIC_SCL = 1;
		usDelay(delaytimes);
		GPIO_SCL_OutStatus(0);
		//		SOFT_IIC_SCL = 0;
		usDelay(delaytimes);
	}
}

/**
 * @brief  读取一个字节
 * @param  ack     1-->发送应答ACK; 0-->发送非应答NACK
 * @retval receive 返回读取到的数据
 */
int8_t Soft_iic_Read()
{
	int8_t i, receive = 0;
	SDA_IN();                             //SDA
	for (i = 0; i < 8; i++)
	{
		GPIO_SCL_OutStatus(0);
		//      SOFT_IIC_SCL = 0;
		usDelay(delaytimes);
		GPIO_SCL_OutStatus(1);
		//		SOFT_IIC_SCL = 1;
		receive <<= 1;
		if (GPIO_SDA_InStatus())
		{
			receive++; //SOFT_IIC_SDA_READ
		}
		usDelay(delaytimes);
	}
	return receive;
}
int32_t IIC_WriteByte(uint8_t writeAddr, const uint8_t buffer)
{
	Soft_iic_start();
	Soft_iic_Write(DEV_ADDR | 0x00);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_Write(writeAddr);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_Write(buffer);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_stop();
	return 0;
}
int32_t IIC_ReadByte(uint8_t readAddr, uint8_t *buffer)
{
	Soft_iic_start();
	Soft_iic_Write(DEV_ADDR | 0x00);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_Write(readAddr);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_start();
	Soft_iic_Write(DEV_ADDR | 0x01);
	if (Soft_wait_ack())
	{
		return -1;
	};
	*buffer = Soft_iic_Read();
	Soft_iic_nack();
	Soft_iic_stop();
	return 0;
}
int32_t IIC_LenWrite(void *ptr, uint8_t writeAddr, const uint8_t *buf,
		uint16_t len)
{
	Soft_iic_start();
	Soft_iic_Write(DEV_ADDR | 0x00);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_Write(writeAddr);
	if (Soft_wait_ack())
	{
		return -1;
	};
	for (int i = 0; i < len; i++)
	{
		Soft_iic_Write(buf[i]);
		if (Soft_wait_ack())
		{
			return -1;
		};
	}
	Soft_iic_stop();
	return 0;
}
int32_t IIC_LenRead(void *ptr, uint8_t readAddr, uint8_t *buf, uint16_t len)
{
	Soft_iic_start();
	Soft_iic_Write(DEV_ADDR | 0x00);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_Write(readAddr);
	if (Soft_wait_ack())
	{
		return -1;
	};
	Soft_iic_start();
	Soft_iic_Write(DEV_ADDR | 0x01);
	if (Soft_wait_ack())
	{
		return -1;
	};
	while (len)
	{
		if (len == 1)
		{
			*buf = Soft_iic_Read();
			Soft_iic_nack();
		}
		else
		{
			*buf = Soft_iic_Read();
			Soft_iic_ack();
		}
		len--;
		buf++;
	}
	Soft_iic_stop();
	return 0;
}

/***********************************end file by:jack***********************************/

